package com.scalar.chiptrack.adaptor;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.TreeWalker;

import com.scalar.ScalarException;
import com.scalar.chiptrack.utils.ConfigManager;

public final class AdaptorXmlHandler{
	
	//Contants nodes from adaptor_list.xml
    public final String ROOT_ELEMENT = "adaptorlist";
    public final String DEF_EMAIL_ELEMENT = "default-email-accounts";
    public final String EMAIL_ELEMENT= "email-id";
    public final String VENDOR_ELEMENT = "vendor";
    public final String VENDOR_ATT_1 = "name";
    public final String ADAPTOR_ELEMENT = "adaptor";
    public final String CLASSNAME_ELEMENT = "class-name";
    public final String PARSER_ELEMENT = "parser";
    public final String PROCESS_ELEMENT = "process";
    public final boolean DEBUG = false;
    
    public String m_configFile = null;
    public Document m_document = null;
    
    public ArrayList m_defaultEmailList = new ArrayList();
    public LinkedHashMap m_adaptorMap = new LinkedHashMap();
    
    public AdaptorXmlHandler() throws ScalarException{
    	
    	m_configFile = ConfigManager.getAdaptorListFile();
    	
    	if(DEBUG){
    		System.out.println("Adaptor Config File Name = "+m_configFile);
    	}
        if (isValidFile (m_configFile) == false) {
            throw new ScalarException ("No/Invalid config file specified for Adaptor list");
        }
        
        try {
        	
 			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    		DocumentBuilder builder = factory.newDocumentBuilder();
    		m_document = builder.parse(m_configFile);
    		
    		constructList();
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new ScalarException ("Exception while reading Adaptor List config file", e);
        }
    }
    
    public ArrayList getDefaultEmailList(){
    	return m_defaultEmailList;
    }
    
    public LinkedHashMap getAdaptorList(){
    	return m_adaptorMap;
    }
    
    public void constructList() throws ScalarException{
    	
    	NodeList list = m_document.getElementsByTagName(VENDOR_ELEMENT);
    	NodeList emailList = m_document.getElementsByTagName(DEF_EMAIL_ELEMENT);
    	
    	processEmailNodes(emailList);
    	processVendorNodes(list);
    }
    
    public void processVendorNodes(NodeList list) throws ScalarException{
    	
    	Adaptor adaptor = null;
    	ArrayList processList =null; 
    	
    	for(int i=0; i<list.getLength(); i++){
    		
    		Node node = list.item(i);
    		Element e = (Element)node;
    		adaptor = new Adaptor();
    		processList = new ArrayList();
    		adaptor.setVendorName (e.getAttribute(VENDOR_ATT_1));
    		
    		if(DEBUG){
    			System.out.println("Main Node = " + node.getNodeName()+"; name="+e.getAttribute(VENDOR_ATT_1));
    		}
    		
			TreeWalker tw  = getTreeWalker(node);
			
			processVendorNodes(tw, processList);
			adaptor.setAdaptorList(processList);
			m_adaptorMap.put(adaptor.getVendorName(), adaptor);
			adaptor = null;
    	}
    }
    
    public TreeWalker getTreeWalker(Node node){
    	
    	AdaptorFilter filter = new AdaptorFilter();
    	TreeWalker tw = ((DocumentTraversal)m_document).createTreeWalker(node, NodeFilter.SHOW_ELEMENT, filter, true);
    	return tw;
    }
    
    public void processVendorNodes(TreeWalker tw, ArrayList processList) throws ScalarException{
    	
    	Node node = tw.getCurrentNode();
    	
    	for(Node child = tw.firstChild(); child!= null; child = tw.nextSibling()){
    		Element e = (Element)child;
    		if(DEBUG){
    			System.out.println("\t Child = "+child.getNodeName()+"; name="+e.getAttribute(VENDOR_ATT_1));
    		}
    		
    		AdaptorList adaptorList = new AdaptorList();
    		adaptorList.setProcessName(e.getAttribute(VENDOR_ATT_1));
 			parsingProcessNodes(e, adaptorList);
 			processList.add(adaptorList);
 			
 			adaptorList = null;
    	}
    	
    	tw.setCurrentNode(node);
    }
    
    public void processEmailNodes(NodeList emailList) throws ScalarException{
    	
    	for(int i=0; i<emailList.getLength(); i++){	
    		Element e = (Element)emailList.item(i);	
    		TreeWalker tw = getTreeWalker(e);
    		if(DEBUG){
    			System.out.println(processTextNode((Element)tw.firstChild()));
    		}
    	}
    }
    
    public void parsingProcessNodes(Element e, AdaptorList adaptorList) throws ScalarException{
    	TreeWalker tw  = getTreeWalker(e);
    	Element firstChild = (Element)tw.firstChild();
    	Element nextSibling = (Element)tw.nextSibling();
    	
    	if(firstChild != null){
    		if(DEBUG){
    			System.out.print("\t\t firstChild = "+firstChild.getNodeName());
    		}
    		if(firstChild.getNodeName().equalsIgnoreCase(ADAPTOR_ELEMENT)) {
    			parsingAdaptorAndParserNodes(firstChild, adaptorList,ADAPTOR_ELEMENT);
    		}
    		if(firstChild.getNodeName().equalsIgnoreCase(PARSER_ELEMENT)) {
    			parsingAdaptorAndParserNodes(firstChild, adaptorList, PARSER_ELEMENT);
    		}
    	}
    	
    	if(nextSibling != null){
    		if(DEBUG){
    			System.out.print("\t\t sibling="+nextSibling.getNodeName());
    		}
    		if(nextSibling.getNodeName().equalsIgnoreCase(PARSER_ELEMENT)) {
    			parsingAdaptorAndParserNodes(nextSibling, adaptorList, PARSER_ELEMENT);
    		}
    		if(nextSibling.getNodeName().equalsIgnoreCase(ADAPTOR_ELEMENT)) {
    			parsingAdaptorAndParserNodes(nextSibling, adaptorList, ADAPTOR_ELEMENT);
    		}
    	}
    }
    
    public void parsingAdaptorAndParserNodes(Element e, AdaptorList adaptorList, String nodeName) throws ScalarException{
    	
    	TreeWalker tw  = getTreeWalker(e);
    	Element firstChild = (Element)tw.firstChild();
    	
    	if(firstChild != null){
    		if(firstChild.getNodeName().equalsIgnoreCase(CLASSNAME_ELEMENT)) {
    			if( (nodeName != null) && nodeName.equalsIgnoreCase(ADAPTOR_ELEMENT)){
    				adaptorList.setAdaptorClassName(processTextNode(firstChild));
    			}
    			if( (nodeName != null) && nodeName.equalsIgnoreCase(PARSER_ELEMENT)){
    				adaptorList.setParserClassName(processTextNode(firstChild));
    			}
    		}
    	}
    }
    
    public String processTextNode(Element node) throws ScalarException{
    	
    	Node child = node.getFirstChild();
    	if(child != null){
    		if(DEBUG){
    			System.out.println("\t Value = "+child.getNodeValue());
    		}
    		
    		return child.getNodeValue();
    		
    	}else{
    		throw new ScalarException("attribute doesn't have any value");
    	}
    	
    }
    
    private boolean isValidFile (String fileName) {
     
        if (fileName == null) {
            return false;
        }
        File file = new File (fileName);
        if (file.exists() == false) {
            return false;
        }
        if (file.isFile() == false) {
            return false;
        }
        if (file.canRead() == false) {
            return false;
        }
        
        return true;
    }
    
    class AdaptorFilter implements NodeFilter{
    	public short acceptNode(Node n){
    		if(n.getNodeType() == Node.ELEMENT_NODE){
    			if(n.getNodeName().equalsIgnoreCase(ADAPTOR_ELEMENT)
    				|| n.getNodeName().equalsIgnoreCase(PROCESS_ELEMENT)
    				|| n.getNodeName().equalsIgnoreCase(PARSER_ELEMENT)
    				|| n.getNodeName().equalsIgnoreCase(CLASSNAME_ELEMENT)
    				|| n.getNodeName().equalsIgnoreCase(EMAIL_ELEMENT)){
    			
    				return FILTER_ACCEPT;
    			}
    		}
    		
    		return FILTER_SKIP;
    	}
    }
    
    public static void main(String[] args){
    	try{
    		
    		AdaptorXmlHandler handler = new AdaptorXmlHandler();
    		
    		LinkedHashMap map = handler.getAdaptorList();
			Iterator it = map.keySet().iterator();
			while(it.hasNext()){
				String key = (String)it.next();
				System.out.println("Key = "+key);
				Adaptor adaptor = (Adaptor)map.get(key);
				ArrayList list = adaptor.getAdaptorList();
				
				Iterator its = list.iterator();
			    while(its.hasNext()){
			    	System.out.println(its.next());
			    }
			}
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    }
}